UI pass: typography, theme toggle, backlink cards, TOC hierarchy, self-hosted fonts, MCP shell#636
Merged
UI pass: typography, theme toggle, backlink cards, TOC hierarchy, self-hosted fonts, MCP shell#636
Conversation
Typography: Fraunces (variable serif) + JetBrains Mono replace the system stack. Per-context opsz/SOFT/WONK variation tuning gives display headings vs. prose vs. sidebar distinct voices from one font file. Theme colour: the full-bleed primary banner on note-title is replaced with a left-accent bar + primary-coloured heading text, so the themed colour is expressive without shouting. Wikilinks drop the pill background in favour of bold primary text with a hover underline. Backlinks: rendered as a responsive card grid, each with a themed left-border accent and the context excerpt inline. Folgezettel tree rails: nested sidebar levels get a subtle left-border rail so depth is visible at a glance. TODOs addressed: - TOC scroll-spy: window.onscroll loop → IntersectionObserver (issue #520) - Task-lists: `li:has(> svg.--ema-checkbox)` + flex for proper alignment, no stray disc bullets - Callout background: naive "${color}10" hex-suffix → color-mix() - External-link glyph: hardcoded gray SVG → mask-image + currentColor, one rule for light and dark - kbd: heavy 3D shadows → flat border with theme-variable colours - Sidebar sizing: inline <style> workaround replaced with Tailwind v4 md:min-w-52/xl:min-w-72 - Mobile breadcrumb: cramped icon row → overflow-x-auto trail Footnotes: scale-x-90 squish + ad-hoc header/indent → semantic <aside> + <ol> with mono markers and proper spacing. Nested list margins tightened so a bulleted sub-list inside an ordered item doesn't push siblings apart. Chrome DevTools MCP: .mcp.json now dispatches to a just recipe that runs chrome-devtools-mcp from a standalone shell.nix at nix/chrome-devtools/shell.nix. Chromium is bundled (Emanote is the consumer, following the boundary from juspay/kolu#650), so the MCP works on machines without a system Chrome. justfile: {{nix_shell}} auto-detect prefix lets `just run`/`just test`/etc. work both inside and outside the Nix devshell.
Swap hardcoded #3b82f6/#eff6ff/#1d4ed8 (blue) for var(--color-primary-*). On pages that set template.theme: green (or any other palette), the active TOC marker now tracks the site colourway instead of staying blue.
Three voices now: - Fraunces (serif, variable) — display headings and prose body - Inter (sans) — sidebar, breadcrumbs, TOC, metadata chrome - JetBrains Mono — code Having the chrome in a dedicated UI sans at small sizes reads tighter than Fraunces-everywhere (kolu.dev's approach) while keeping the distinctive Fraunces personality where it matters.
Class-based dark variant:
- @custom-variant dark (&:where(.dark, .dark *)) in both the
Tailwind CLI input (Tailwind.hs) and the browser CDN
config (tailwindBrowserConfig), so dark:* classes activate
from an html.dark class.
Early-load script in base.tpl reads localStorage before first
paint (with OS preference as fallback) and sets the class plus
color-scheme, avoiding a light→dark flash on reload.
Toggle button in the sidebar header flips the html.dark class,
persists the choice, and reloads when a mermaid diagram is on
the page (mermaid reads the scheme at init only).
Fixed stork-search-head.tpl: it was initializing
`window.emanote = {}` destructively, clobbering the theme
helper. Changed to `window.emanote = window.emanote || {}`
so later modules can co-exist.
Body prose font-variation-settings tightened to 'opsz' 14,
'SOFT' 60 — the same values kolu.dev uses for their body, which
gives Fraunces its warm humanist feel at reading sizes.
- skylighting.css: switch prefers-color-scheme media queries to a .dark class selector so syntax highlighting follows the manual toggle. - backlinks.tpl: drop the heavy top/bottom/right borders; keep the primary-colour left accent + subtle shadow. - stork-search: load both light and dark stylesheets unconditionally and pick the wrapper class from the .dark class on <html> (via a MutationObserver) instead of matchMedia, so the search dialog tracks the user's manual theme choice.
The backlink card already has a thick primary left accent; the thin primary-200 rail on the inner context div doubled up with it.
- Fonts: swap Google Fonts CDN for self-hosted bundle under _emanote-static/fonts/ (woff2 + generated fonts.css with relative URLs). Static sites no longer reach out to fonts.gstatic.com. Typography: Lora (prose), Space Grotesk (UI chrome + headings), Space Mono (code). - Note title: restore the Emanote brand treatment (bg-primary-600/primary-800, white centered, rounded-2xl). - Backlinks: drop outer panel bg/border/shadow; thinner border-l-2 primary-400 per card; make the block pick up the sans font by scoping #backlinks into the UI-chrome selector. - Wikilinks: subtle primary-50/primary-950 hover background (no underline); external links get hover-only underline. - Context: remove redundant inner left border rail. - Sidebar: drop tag-index + expand-tree shortcut icons — search and theme toggle only. - No-sidebar layout: mirror the sidebar's theme toggle in the top-right button row so neuron-style pages can flip theme too. - TOC: visual hierarchy by depth — each nested UL level steps down font-size and colour so long outlines stay scannable; active-item rule re-scoped under #toc so it still wins.
Add _emanote-static/fonts/*.{woff2,css} to data-files so the Nix
build packages the bundled Lora/Space Grotesk/Space Mono fonts
into the static layer. Without this, generated sites 404 on
fonts.css and the link checker fails.
srid
commented
Apr 21, 2026
…ate.sh - docs/guide/html-template/fonts.md: swap the Fraunces + JetBrains Mono blurb for the new self-hosted Lora + Space Grotesk + Space Mono stack; mention the --font-serif/sans/mono CSS-variable override path. - docs/guide/html-template/dark-mode.md: drop the stale 'automatic via prefers-color-scheme + browser extension to toggle' framing; document the manual toggle, localStorage persistence, and the .dark class conventions. - CHANGELOG: expand the 1.6.0.0 Unreleased UI revamp entry with typography, theme toggle, backlinks, TOC, wikilinks, and sidebar simplifications from this PR. - fonts/update.sh + justfile fonts-update: reproducible re-download of the self-hosted Google Fonts bundle. Script is idempotent (skips already-present blobs) and explains the hash-based filenames that Google's CDN hands back.
- nix/chrome-devtools/shell.nix: pull nixpkgs straight from the top-level flake.lock (builtins.fetchTree with owner/repo/rev/ narHash) instead of tracking nixos-unstable independently. One pin to maintain. - justfile: drop the fonts-update recipe; invoke the script directly when needed. - CHANGELOG: trim the 1.6.0.0 UI-revamp entry to three lines.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A top-to-bottom visual refresh of the default Emanote theme, arrived at through iterative feedback against the live dev server. The goal was to land somewhere colourful and fun but not jarring — evocative of neuron.zettel.page's character, suitable for Zettelkasten notes as much as tech docs or personal pages — without making the theme feel like a template everyone else already uses.
What changed
Typography. Swapped the old Source Serif stack for Lora (prose), Space Grotesk (UI chrome + headings), and Space Mono (code). All three are self-hosted under
_emanote-static/fonts/as woff2 + a generatedfonts.csswith relative URLs, so generated static sites no longer phone home tofonts.gstatic.com.Theme toggle. A persistent dark/light mode toggle lives in the sidebar (and, critically, in the no-sidebar "neuron-style" layout too, via the top-right button row). State is kept in
localStorage; an early-load script inbase.tplapplies the.darkclass before first paint to avoid a flash of wrong theme. Everything previously keyed offprefers-color-scheme—skylighting.css, the stork search dialog — was rewired to the manual toggle via.darkclass selectors (and a tinyMutationObserverin the stork wrapper for live swap).Note title is back to the Emanote brand treatment:
bg-primary-600, white, centered,rounded-2xl. That look is the Emanote brand; an earlier iteration stripped it and it immediately felt generic.Backlinks. Re-done as a 2-column card grid with a thin primary left-accent (
border-l-2) and subtle shadow, no outer panel bg/border. The "Links to this page" block now picks up the sans font via#backlinksbeing added to the UI-chrome selector.Links. Wikilinks get a subtle primary-50/primary-950 hover background (no underline); external links switch to hover-only underline. The wikilink background uses
-mx-1 px-1 roundedso text doesn't reflow on hover.TOC. Replaced the old
window.onscrollscroll-spy with anIntersectionObserver(#520's long-standing TODO). On top of that: depth-based visual hierarchy — each nested<ul>level in the "On this page" list steps down font-size and colour, so a 30-heading page stays scannable at a glance. Active-item styling now usesvar(--color-primary-*)so per-site theme overrides flow through cleanly.Sidebar. Removed the tag-index and expand-tree shortcut icons — search and theme toggle only. Folgezettel tree depth rails (
#sidebar .pl-2 .pl-2 { border-left: ... }) keep the nested structure legible.Smaller polishes. Callouts use
color-mix(in srgb, ${color} 8%, transparent)for tint backgrounds (no more naive${color}10). External-link glyphs are drawn withmask-image+currentColorso they inherit link colour in both themes.kbdrestyled with theme variables. Task-list items use:has(> svg.--ema-checkbox)to swap the disc bullet for a flex-aligned checkbox. Footnotes re-done as a semantic<aside> + <ol>instead of the oldscale-x-90squish. Nested-list vertical rhythm fixed. Mermaid diagrams re-render on theme toggle.Infra/MCP. Added
{{nix_shell}}prefixing injustfilesojust runworks outside a Nix shell, plus a thinjust mcp-chrome-devtoolsrecipe invoked from.mcp.json. A newnix/chrome-devtools/shell.nixbundles Chromium + pinschrome-devtools-mcp@0.21.0(adapted from juspay/kolu#650) so the chrome-devtools MCP server has a headless browser to drive.Docs.
docs/guide/html-template/fonts.mdupdated to reflect the new default stack.Notable tradeoffs
Test plan
/yaml-config) and confirm the TOC shows depth-based hierarchy and the active-item tracker follows scroll.cabal build allandcabal test allsucceed.fonts.googleapis.comnetwork requests.